package com.margo.project.zipkin.mysql.mybatis.interceptor;


import java.sql.Statement;
import java.util.List;
import java.util.Properties;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import brave.Span;
import brave.propagation.ThreadLocalSpan;

@Component
@Intercepts({
		@Signature(type = StatementHandler.class, method = "query", args = { Statement.class, ResultHandler.class }),
		@Signature(type = StatementHandler.class, method = "update", args = { Statement.class }),
		@Signature(type = StatementHandler.class, method = "batch", args = { Statement.class }) })
public class MargoSqlInterceptor implements Interceptor{

	Logger logger=LoggerFactory.getLogger(this.getClass());
	
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		Object target = invocation.getTarget();

		StatementHandler statementHandler = (StatementHandler) target;
		try {
			preProcess(statementHandler);
			return invocation.proceed();
		} finally {
			postProcess();
		}
	}

	@Override
	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	@Override
	public void setProperties(Properties properties) {
		// TODO Auto-generated method stub
	}
	
	public void preProcess(StatementHandler statementHandler) {
	    // Gets the next span (and places it in scope) so code between here and postProcess can read it
	    Span span = ThreadLocalSpan.CURRENT_TRACER.next();
	    if (span == null || span.isNoop()) return;
	
	    BoundSql boundSql = statementHandler.getBoundSql();
		String sql = boundSql.getSql();
	    span.tag("sql.query", sql);
	    
	    Object parameterObject = boundSql.getParameterObject();
		List<ParameterMapping> parameterMappingList = boundSql.getParameterMappings();
		logger.info(sql);
		if(parameterObject !=null) {
			span.tag("sql.parameterObject", parameterObject.toString());
			logger.info(parameterObject.toString());	
		}
		if(parameterMappingList !=null) {
			span.tag("sql.parameterMappingList", parameterMappingList.toString());
			logger.info(parameterMappingList.toString());	
		}
	    String remoteServiceName = "mysql-zipkinServiceName";
	    span.remoteServiceName(remoteServiceName);
	    span.start();
	}

	public void postProcess() {
	    Span span = ThreadLocalSpan.CURRENT_TRACER.remove();
	    if (span == null || span.isNoop()) return;
	    span.finish();

    }
}
